package org.videopractice.network;

import org.videopractice.network.codec.MessageDecoder;
import org.videopractice.network.codec.MessageEncoder;
import org.videopractice.network.handler.ClientMessageHandler;

import java.net.InetSocketAddress;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * 客户端服务：接受消息
 */
public class ClientServer {

    public static final ClientServer SERVER = new ClientServer();

    private final int socketPort = 1215;

    private boolean isStop = true;
    private EventLoopGroup group;
    private ChannelFuture channelFuture;

    private ClientServer() {

    }

    private void onConnect(String address, int port) {
        if (!this.isStop)
            return;
        try {
            this.isStop = false;
            this.group = new NioEventLoopGroup(1);
            Bootstrap clientBootstrap = new Bootstrap();
            clientBootstrap.group(this.group).channel(NioSocketChannel.class)
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .option(ChannelOption.SO_KEEPALIVE, Boolean.valueOf(true))
                    .option(ChannelOption.TCP_NODELAY, Boolean.valueOf(true))
                    .handler(new ChannelInitializer<SocketChannel>(){
                        @Override
                        protected void initChannel(SocketChannel paramAnonymousSocketChannel){
                            ChannelPipeline channelPipeline = paramAnonymousSocketChannel.pipeline();
                            // 当有操作超出指定空闲秒数时，便会触发{@link MessageTransportHandler#userEventTriggered}事件
                            // 服务端设置读超时时间为180秒
                            channelPipeline.addLast(new IdleStateHandler(180, 0, 0));
                            channelPipeline.addLast(new ChannelHandler[] { new MessageDecoder() });
                            channelPipeline.addLast(new ChannelHandler[] { new LengthFieldPrepender(4) });
                            channelPipeline.addLast(new ChannelHandler[] { new MessageEncoder() });
                            channelPipeline.addLast(new ClientMessageHandler());
                        }
                    });

            InetSocketAddress socketAddress = new InetSocketAddress(address, port);
            this.channelFuture = clientBootstrap.connect(socketAddress).sync();
            this.channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } finally {
            this.isStop = true;
            try {
                this.group.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void connect(String socketAddress) {
        new Thread() {
            public void run() {
                try {
                    onConnect(socketAddress, socketPort);
                    return;
                } catch (Exception localException) {
                    localException.printStackTrace();
                }
            }
        }.start();
    }

    public void close() {
        this.isStop = true;
        if (this.group != null) {
            try {
                this.group.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.group = null;
        }
    }

} 
